package nl.unimaas.micc.umsnooker.simulation;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.LogManager;

import nl.unimaas.micc.umsnooker.domain.BilliardBall;
import nl.unimaas.micc.umsnooker.domain.Cue;
import nl.unimaas.micc.umsnooker.domain.Table;
import nl.unimaas.micc.umsnooker.math.BairstowSolver;
import nl.unimaas.micc.umsnooker.simulation.InTimeSimulationBenchmarkBreakoff.EventCounter;
import nl.unimaas.micc.umsnooker.simulation.event.BallCollision;
import nl.unimaas.micc.umsnooker.simulation.event.CueInteraction;
import nl.unimaas.micc.umsnooker.simulation.event.Event;
import nl.unimaas.micc.umsnooker.simulation.physics.Physics;

import com.jme.math.Vector3f;

import junit.framework.TestCase;

public class InTimeSimulationBenchmarkAfterBreakoff extends TestCase
{
	private Set<BilliardBall> balls;
	private Table table;
	private Set<Event> initEvents;
	private BilliardBall cueBall;
	private Cue cue;

	@Override
	protected void setUp() throws Exception
	{
    	try
		{
			LogManager.getLogManager().readConfiguration(new FileInputStream("logging.properties"));
		}
		catch (SecurityException e)
		{
			e.printStackTrace();
		}
		catch (FileNotFoundException e)
		{
			e.printStackTrace();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		
		super.setUp();

		table = new Table(1.778f, 3.569f, .737f, .292f, .324f, .0525f / 2f,
				.045f, .045f);

		// --> Initialize the cue ball
		Vector3f cueBallPosition = new Vector3f(0.9127058f,2.8819523f, 0.0f );
		cueBall = new BilliardBall(0, BilliardBall.Type.CUE, cueBallPosition);
		// We store all balls in a List:
		balls = new HashSet<BilliardBall>(25);
		balls.add(cueBall);

		Vector3f yellowSpot = new Vector3f(1.181f, 0.737f,0.0f);
		Vector3f greenSpot = new Vector3f(0.597f,0.737f,0.0f);
		Vector3f brownSpot = new Vector3f(0.889f,0.737f,0.0f);
		Vector3f blueSpot = new Vector3f(0.889f,1.7845f,0.0f);
		Vector3f pinkSpot = new Vector3f(0.889f,1.9307778f,0.0f);
		Vector3f blackSpot = new Vector3f(0.8110117f,3.2359529f,0.0f);

		
		// --> Initialize the colored balls
		balls.add(new BilliardBall(2, BilliardBall.Type.YELLOW, yellowSpot));
		balls.add(new BilliardBall(3, BilliardBall.Type.GREEN, greenSpot));
		balls.add(new BilliardBall(4, BilliardBall.Type.BROWN, brownSpot));
		balls.add(new BilliardBall(5, BilliardBall.Type.BLUE, blueSpot));
		balls.add(new BilliardBall(6, BilliardBall.Type.PINK, pinkSpot));
		balls.add(new BilliardBall(7, BilliardBall.Type.BLACK, blackSpot));

		// --> Initialize the red balls
		int id = 8;
		Vector3f[] redSpots = new Vector3f[]{
			new Vector3f(0.09128226f,2.1839066f,0.0f),
			new Vector3f(0.91733927f,2.7783544f,0.0f),
			new Vector3f(0.54502064f,1.6954889f,0.0f),
			new Vector3f(0.67882884f,2.960431f,0.0f),
			new Vector3f(0.9932828f, 2.8183832f,0.0f),
			new Vector3f(0.35969234f,2.7218602f,0.0f),
			new Vector3f(0.49534675f,3.0230997f,0.0f),
			new Vector3f(1.652805f,3.3595042f,0.0f ),
			new Vector3f(0.99818414f, 2.909342f, 0.0f),
			new Vector3f(0.30152494f, 3.536985f, 0.0f),
			new Vector3f(0.16894494f, 3.5342007f, 0.0f),
			new Vector3f(0.48954755f,3.281312f, 0.0f ),
			new Vector3f(0.43450215f, 3.0838614f, 0.0f),
			new Vector3f(1.2141689f, 2.255037f, 0.0f)
		};
		for (Vector3f redSpot : redSpots)
		{
			balls.add(new BilliardBall(id++, BilliardBall.Type.RED, redSpot));
		}

		// --> Configure all balls
		for (BilliardBall ball : balls)
		{
			ball.setRadius(table.getBallRadius());
			ball.setMass(.120f);
			ball.setFriction(0.06f);
			ball.setTime(0);
		}
		
		cue = new Cue(.550f);

		BairstowSolver.THRESHOLD = 5E-6;
		Simulation.TIME_THRESHOLD = 1E-7;
		Simulation.SPACE_THRESHOLD = 1E-6;
		BallCollision.VELOCITY_THRESHOLD = 1E-8f;
		Physics.THRESHOLD = 5E-6;
		System.out.println("CSV file of after-break-benchmark");
		System.out.println("Format:\n Velocity,TotalEventCount,CollisionCount,Runs/second,Time/simulation");
	}

	class EventCounter implements EventHandler{

		private int eventNumber = 0;
		@Override
		public void handle(Event e) {
				eventNumber++;			
		}
		
		private int getNumber(){
			return eventNumber;
		}
	}
	
	class CollisionCounter implements EventHandler{

		private int eventNumber = 0;
		@Override
		public void handle(Event e) {
				if(e instanceof BallCollision)
					eventNumber++;			
		}
		
		private int getNumber(){
			return eventNumber;
		}
	}
	
	public void testSimulation()
	{
		float velocity = .5f;
		float step = .25f;
		float maxValue = 10f;
		while(velocity <= maxValue){
			
			int runs = 100;
			
			long time = System.currentTimeMillis();
			Simulation sim = new InTimeSimulation(balls, table);
			EventCounter counter = new EventCounter();
			sim.addEventHandler(counter);
			CollisionCounter collCounter = new CollisionCounter();
			sim.addEventHandler(collCounter);
			
			for (int i = 0; i < runs; i++)
			{
				initEvents = new HashSet<Event>();
				initEvents.add(new CueInteraction(0, cue, cueBall, 0, 0, 0, 0, velocity));
				sim.init(initEvents);
				sim.finish();
				//sim.reset();
			}
			float result = (System.currentTimeMillis() - time) / 1000f;
			//int eventCount = counter.getNumber();
			System.out.println(velocity + " , " + counter.getNumber()/runs + " , " + collCounter.getNumber()/runs + " , "
					 + runs/result + " , " + result / runs * 1000f);
			velocity+=step;
		}
	}

}
